<template>
    <main class="overflow-hidden relative w-screen h-screen">
        <!-- Decoration -->
        <div
            class="gradient-ball absolute -z-10 left-0 bottom-0 translate-x-[-50%] translate-y-[50%] w-[90vw] aspect-square opacity-15 blob-anim"
        ></div>
        <div
            class="gradient-ball absolute -z-10 right-0 top-0 translate-x-[50%] translate-y-[-50%] w-[90vw] aspect-square opacity-15 blob-anim"
        ></div>

        <!-- Stripes for experimental -->
        <div
            v-show="wbConfig?.config.experimentalFeatures"
            :key="rerenderCounter"
            class="experimental-stripes absolute top-0 left-0 w-full h-[3rem] pointer-events-none z-[10] opacity-15 grayscale"
        ></div>

        <!-- Titlebar -->
        <x-titlebar
            @minimize="handleMinimize()"
            @buttonclick="handleTitleBarEvent"
            class="backdrop-blur-xl bg-neutral-900/50"
        >
            <x-label>WinBoat</x-label>
        </x-titlebar>

        <!-- Updater -->
        <dialog ref="updateDialog">
            <Icon class="text-indigo-400 size-12" icon="mdi:cloud-upload"></Icon>
            <template v-if="manualUpdateRequired">
                <h3 class="mt-2">Manual Guest Server Update Required</h3>
                <div class="max-w-[60vw]">
                    <strong
                        >WinBoat has encountered an issue while trying to update the Guest Server automatically. Please
                        follow the steps below to manually update it:</strong
                    >
                    <ol class="mt-2 list-decimal list-inside">
                        <li>
                            Use VNC over at
                            <a @click="openAnchorLink" :href="novncURL" target="_blank" rel="noopener noreferrer">
                                {{ novncURL }}
                            </a>
                            to access Windows
                        </li>
                        <li>Press Win + R or search for <code>Run</code>, type in <code>services.msc</code></li>
                        <li>Stop the <code>WinBoatGuestServer</code> service by right clicking and pressing "Stop"</li>
                        <li>
                            Download the new Guest Server from
                            <a
                                @click="openAnchorLink"
                                href="https://github.com/TibixDev/winboat/releases"
                                target="_blank"
                                rel="noopener noreferrer"
                            >
                                https://github.com/TibixDev/winboat/releases
                            </a>
                            , you should pick version <strong>{{ appVer }}</strong>
                        </li>
                        <li>Navigate to <code>C:\Program Files\WinBoat</code> and delete the contents</li>
                        <li>Extract the freshly downloaded zip into the same folder</li>
                        <li>
                            Start the <code>WinBoatGuestServer</code> service by right clicking and pressing "Start"
                        </li>
                        <li>If you were using VNC, log out of Windows and close it</li>
                        <li>Restart WinBoat</li>
                    </ol>
                    <p>We're sorry for the inconvenience. 😟</p>
                </div>
            </template>

            <template v-else>
                <h3 class="mt-2" v-if="winboat?.isUpdatingGuestServer.value">Updating Guest Server</h3>
                <h3 class="mt-2" v-else>Guest Server update successful!</h3>
                <p v-if="winboat?.isUpdatingGuestServer.value" class="max-w-[40vw]">
                    The guest is currently running an outdated version of the WinBoat Guest Server. Please wait while we
                    update it to the current version.
                </p>
                <p v-else class="max-w-[40vw]">
                    The WinBoat Guest Server has been updated successfully! You can now close this dialog and continue
                    using the application.
                </p>
            </template>
            <footer v-if="!manualUpdateRequired">
                <x-progressbar v-if="winboat?.isUpdatingGuestServer.value" class="my-4"></x-progressbar>
                <x-button v-else id="close-button" @click="updateDialog!.close()" toggled>
                    <x-label>Close</x-label>
                </x-button>
            </footer>
        </dialog>

        <!-- UI / SetupUI -->
        <div
            v-if="!['SetupUI', 'Migration'].includes($route.name?.toString() || '')"
            class="flex flex-row h-[calc(100vh-2rem)]"
        >
            <x-nav class="flex flex-col flex-none gap-0.5 w-72 backdrop-blur-xl bg-gray-500/10 backdrop-contrast-90">
                <div
                    v-if="winboat?.rdpConnected.value"
                    class="w-full bg-gradient-to-r from-indigo-500 via-indigo-400 to-blue-500 text-white !mt-0 py-1 shadow-md shadow-indigo-500/50 transition-all duration-300 hover:brightness-105 flex flex-row items-center justify-center gap-2"
                >
                    <Icon class="size-5" icon="mdi:remote-desktop"></Icon>
                    <span class="font-semibold text-center"> RDP Session Active </span>
                </div>
                <div class="flex flex-row gap-4 items-center p-4">
                    <img
                        class="w-16 rounded-full"
                        src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b5/Windows_10_Default_Profile_Picture.svg/2048px-Windows_10_Default_Profile_Picture.svg.png"
                        alt="Profile"
                    />
                    <div>
                        <x-label class="text-lg font-semibold">{{ os.userInfo().username }}</x-label>
                        <x-label class="text-[0.8rem]">Local Account</x-label>
                    </div>
                </div>
                <RouterLink
                    v-for="route of routes.filter(
                        (r: RouteRecordRaw) => !['SetupUI', 'Loading', 'Migration'].includes(String(r.name)),
                    )"
                    :to="route.path"
                    :key="route.path"
                >
                    <x-navitem>
                        <Icon class="mr-4 w-5 h-5" :icon="route.meta!.icon as string"></Icon>
                        <x-label>{{ route.name }}</x-label>
                    </x-navitem>
                </RouterLink>
                <div class="flex flex-col justify-end items-center p-4 h-full">
                    <p class="text-xs text-neutral-500">WinBoat Beta v{{ appVer }} {{ isDev ? "Dev" : "Prod" }}</p>
                </div>
            </x-nav>
            <div class="px-5 flex-grow max-h-[calc(100vh-2rem)] overflow-y-auto py-4">
                <div class="flex flex-row gap-2 items-center my-6">
                    <Icon class="w-6 h-6 opacity-60" icon="icon-park-solid:toolkit"></Icon>
                    <h1 class="my-0 text-2xl font-semibold opacity-60">WinBoat</h1>
                    <Icon class="w-6 h-6" icon="bitcoin-icons:caret-right-filled"></Icon>
                    <Icon class="w-6 h-6" :icon="useRoute().meta.icon as string"></Icon>
                    <h1 class="my-0 text-2xl font-semibold">
                        {{ useRoute().name }}
                    </h1>
                </div>
                <router-view v-slot="{ Component }" @rerender="rerenderCounter++">
                    <transition mode="out-in" name="fade">
                        <component :is="Component" />
                    </transition>
                </router-view>
            </div>
        </div>

        <div v-else class="w-full h-[calc(100vh-2rem)]">
            <RouterView />
        </div>
    </main>
</template>

<script setup lang="ts">
import { RouteRecordRaw, RouterLink, useRoute, useRouter } from "vue-router";
import { routes } from "./router";
import { Icon } from "@iconify/vue";
import { onMounted, onUnmounted, ref, useTemplateRef, watch } from "vue";
import { isInstalled } from "./lib/install";
import { Winboat, logger } from "./lib/winboat";
import { openAnchorLink } from "./utils/openLink";
import { WinboatConfig } from "./lib/config";
import { USBManager } from "./lib/usbmanager";
import { setIntervalImmediately } from "./utils/interval";
import { CommonPorts, getActiveHostPort } from "./lib/containers/common";
const { BrowserWindow }: typeof import("@electron/remote") = require("@electron/remote");
const os: typeof import("os") = require("node:os");

const $router = useRouter();
const $route = useRoute();
const appVer = import.meta.env.VITE_APP_VERSION;
const isDev = import.meta.env.DEV;
let winboat: Winboat | null;
let wbConfig: WinboatConfig | null;

let updateTimeout: NodeJS.Timeout | null = null;
const manualUpdateRequired = ref(false);
const MANUAL_UPDATE_TIMEOUT = 60000; // 60 seconds
const updateDialog = useTemplateRef("updateDialog");
// TODO: Hack for non-reactive data
const rerenderCounter = ref(0);
const novncURL = ref("");
let animationCheckInterval: NodeJS.Timeout | null = null;

onMounted(async () => {
    const winboatInstalled = await isInstalled();
    if (winboatInstalled) {
        wbConfig = WinboatConfig.getInstance(); // Instantiate singleton class
        winboat = Winboat.getInstance(); // Instantiate singleton class
        USBManager.getInstance(); // Instantiate singleton class

        if (!wbConfig.config.performedComposeMigrations) {
            $router.push("/migration");
            logger.info("Performing migrations for 0.9.0");

            // Compose migration
            if (await winboat.containerMgr!.exists()) {
                logger.info("Composing down current WinBoat container");
                await winboat.containerMgr!.compose("down");
            }

            const currentCompose = Winboat.readCompose(winboat.containerMgr!.composeFilePath);
            const defaultCompose = winboat.containerMgr!.defaultCompose;

            currentCompose.services.windows.ports = defaultCompose.services.windows.ports;

            winboat.containerMgr!.writeCompose(currentCompose);

            logger.info("Composing up WinBoat container");
            await winboat.containerMgr!.compose("up", ["--no-start"]);

            wbConfig!.config.performedComposeMigrations = true;
        }

        $router.push("/home");
    } else {
        console.log("Not installed, redirecting to setup...");
        $router.push("/setup");
    }

    // Apply or remove disable-animations class based on config
    const updateAnimationClass = () => {
        if (wbConfig?.config.disableAnimations) {
            document.body.classList.add("disable-animations");
            console.log("Animations disabled");
        } else {
            document.body.classList.remove("disable-animations");
            console.log("Animations enabled");
        }
    };

    // Poll for config changes since the Proxy doesn't trigger Vue reactivity
    // This is similar to how rerenderCounter is used elsewhere in the codebase
    // Start with undefined so that the first call will always apply the current state
    let lastAnimationState: boolean | undefined = undefined;
    animationCheckInterval = setIntervalImmediately(() => {
        const currentState = wbConfig?.config.disableAnimations;
        if (currentState !== lastAnimationState) {
            lastAnimationState = currentState;
            updateAnimationClass();
            rerenderCounter.value++; // Force re-render to update transitions
        }
    }, 1000); // Check every 1000ms

    // Watch for guest server updates and show dialog
    watch(
        () => winboat?.isUpdatingGuestServer.value,
        isUpdating => {
            if (isUpdating === true) {
                novncURL.value = `http://127.0.0.1:${getActiveHostPort(winboat?.containerMgr!, CommonPorts.NOVNC)}`;
                updateDialog.value!.showModal();
                // Prepare the timeout to show manual update required after 45 seconds
                updateTimeout = setTimeout(() => {
                    manualUpdateRequired.value = true;
                }, MANUAL_UPDATE_TIMEOUT);
            } else {
                // Clear the timeout if the update finished before the timeout
                if (updateTimeout) {
                    clearTimeout(updateTimeout);
                    updateTimeout = null;
                }
                manualUpdateRequired.value = false;
            }
        },
    );
});

onUnmounted(() => {
    // Clean up the interval when component unmounts
    if (animationCheckInterval) {
        clearInterval(animationCheckInterval);
    }
});

function handleMinimize() {
    console.log("Minimize");
    window.electronAPI.minimizeWindow();
}

function handleTitleBarEvent(e: CustomEvent) {
    console.log("TitleBarEvt", e);
    switch (e.detail) {
        case "close":
            BrowserWindow.getFocusedWindow()!.close();
            break;
        case "maximize":
            if (BrowserWindow.getFocusedWindow()!.isMaximized()) {
                BrowserWindow.getFocusedWindow()!.unmaximize();
            } else {
                BrowserWindow.getFocusedWindow()!.maximize();
            }
            break;
        case "minimize":
            BrowserWindow.getFocusedWindow()!.minimize();
            break;
    }
}
</script>

<style>
dialog::backdrop {
    pointer-events: none;
    backdrop-filter: blur(8px);
}

.gradient-ball {
    border-radius: 99999px;
    background:
        linear-gradient(197.37deg, #7450db -0.38%, rgba(138, 234, 240, 0) 101.89%),
        linear-gradient(115.93deg, #3e88f6 4.86%, rgba(62, 180, 246, 0.33) 38.05%, rgba(62, 235, 246, 0) 74.14%),
        radial-gradient(
            56.47% 76.87% at 6.92% 7.55%,
            rgba(62, 136, 246, 0.7) 0%,
            rgba(62, 158, 246, 0.182) 52.16%,
            rgba(62, 246, 246, 0) 100%
        ),
        linear-gradient(306.53deg, #2ee4e3 19.83%, rgba(46, 228, 227, 0) 97.33%);
    background-blend-mode: normal, normal, normal, normal, normal, normal;
    filter: blur(200px);
}

@keyframes blob {
    from {
        filter: hue-rotate(0deg) blur(200px);
    }
    to {
        filter: hue-rotate(45deg) blur(200px);
    }
}

.blob-anim {
    animation: blob 5s linear infinite;
    animation-direction: alternate-reverse;
}

.fade-enter-active,
.fade-leave-active {
    transition: all 0.2s ease;
}

.fade-enter-from {
    opacity: 0;
}

.fade-leave-to {
    opacity: 0;
}

/* Stripes for the top of the window to indicate experimental features enabled */
.experimental-stripes {
    background: repeating-linear-gradient(
        45deg,
        #ffffff00,
        #ffffff00 25px,
        rgb(129 140 248) 25px,
        rgb(129 140 248) 50px
    );
    -webkit-mask-image: -webkit-gradient(linear, left 0%, left bottom, from(rgba(0, 0, 0, 1)), to(rgba(0, 0, 0, 0)));
}

/* Disable all animations when the setting is enabled */
body.disable-animations,
body.disable-animations *,
body.disable-animations *::before,
body.disable-animations *::after {
    animation: none !important;
    transition: none !important;
}

/* Specifically disable Vue transition components */
body.disable-animations .fade-enter-active,
body.disable-animations .fade-leave-active,
body.disable-animations .devices-move,
body.disable-animations .devices-enter-active,
body.disable-animations .devices-leave-active,
body.disable-animations .menu-move,
body.disable-animations .menu-enter-active,
body.disable-animations .menu-leave-active,
body.disable-animations .apps-move,
body.disable-animations .apps-enter-active,
body.disable-animations .apps-leave-active,
body.disable-animations .bounce-enter-active,
body.disable-animations .bounce-leave-active,
body.disable-animations .bouncedown-enter-active,
body.disable-animations .bouncedown-leave-active,
body.disable-animations .bounce-in,
body.disable-animations .bouncedown-in {
    transition: none !important;
    animation: none !important;
}

/* Disable keyframe animations */
body.disable-animations .blob-anim {
    animation: none !important;
}
</style>
